package com.navinfo.platform.trip.common.arithmetic.data;

import com.navinfo.platform.trip.common.arithmetic.enums.EventType;
import com.navinfo.platform.trip.common.fuelleak.FuelLeakLocation;
import com.navinfo.platform.trip.common.pojo.TripInfo;
import com.navinfo.platform.trip.common.util.GsonUtils;
import com.navinfo.platform.trip.common.vehicle.VehicleInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 算法链的中间缓存数据，所有车厂的全量字段
 * @author web
 */
@SuppressWarnings("unchecked")
public class DrivingData implements Serializable {
    private static Logger logger = LoggerFactory.getLogger(DrivingData.class);

    /**
     * 算法链的公共缓存（当前点和上个点的公共数据）<br/>
     * "commonData": {
     *     "speedMs": 32.38,					速度（m/s）
     *     "speedKmh": 116, 					速度（km/h）
     *     "acceleratedSpeed": 0.01, 		加速度
     *     "latitude": 123456797, 			纬度
     *     "longitude": 42345686, 			经度
     *     "height": 1130, 					高程
     *     "engineOutputTorque": 12, 		发动机输出扭矩
     *     "rotation": 3551,					转速
     *     "accelerator": 12.0,				油门
     *     "brake": 0,						制动信号
     *     "gear": 9,							档位
     *     "clutchSwitch": 0, 				离合器开关
     *     "realTimeOilConsumption": 6, 	发动机瞬时油耗
     *     "fuelConsumptionRate": 15, 		发动机燃油消耗率
     *     "gpsDirection": 0, 				GPS方向
     *     "gpsTime": 1522721068000, 		GPS时间
     *     "dffDistance": 2299, 				距离差
     *     "dffTime": 71000,					时间差
     *     "dffOil": 296,						油耗差
     *     "lowRotationTime": 0, 			发动机转速低于500持续时间
     *     "terminalId": "15940452871", 	通信号
     *     "lastGpsTime": 1522721068000, 	上个点的GPS时间
     *     "lastRotation": 3551, 			上个点的转速
     *     "lastSpeedMs": 32.38 			上个点的速度（m/s）
     * },
     */
    private CommonData commonData = new CommonData();

    /**
     * 算法链的统计缓存<br/>
     * "statisticData": {
     *      引擎超转速变量
     *     "RotationOver": {
     *         "mileage": 11099.0,				引擎超转速行驶距离
     *         "timeMs": 355000,					行驶时长
     *         "oil": 1440.0,						行驶油量
     *         "sumRotation": 22659,				转速之和
     *         "number": 9,						位置点数
     *         "avgRotation": 2517,				平均转速
     *         "maxRotation": 3551,				最大转数
     *         "preOver": true					上个点是否超转速
     *     },
     * }
     */
    private Map<String, Object> statisticData = new ConcurrentHashMap<>();

    /**
     * 算法链的事件缓存<br/>
     * "eventData": {
     *     引擎超转速事件（其他事件类似）
     *     "engineOverSpeed": {
     *         "startGpsTime": 1522720713000,		事件开始时间
     *         "startLatitude": 123456792,			开始纬度
     *         "startLongitude": 42345681,			开始经度
     *         "startHeight": 1125,					开始高程
     *         "startSpeed": 106,					开始速度
     *         "startGpsDirection": 0,				开始方向
     *         "stopGpsTime": 0,					事件结束时间
     *         "stopLatitude": 0,					结束纬度
     *         "stopLongitude": 0,					结束经度
     *         "stopHeight": 0,						结束高程
     *         "stopSpeed": 0,						结束速度
     *         "stopGpsDirection": 0,				结束方向
     *         "duration": 0,						持续时间
     *         "event": "engineOverSpeed",			事件类型
     *         "extendField01": 11099,				扩展1
     *         "extendField02": 1440,				扩展2
     *         "extendField03": 0,					扩展3
     *         "extendField04": 0,					扩展4
     *         "extendField05": 0,					扩展5
     *         "extendField06": 0,					扩展6
     *         "extendField07": 0,					扩展7
     *         "extendField08": 0,					扩展8
     *         "extendField09": 0,					扩展9
     *         "extendField10": 0					扩展10
     *     }
     * }
     */
    private Map<EventType, OuterEventData> eventData = new ConcurrentHashMap<>();

    /**
     * 算法链输出的事件列表
     */
    private List<OuterEventData> outerEvent = new ArrayList<>();

    /**
     * 行程的开始结束基本信息<br/>
     * "tripInfo": {
     *     "startTime": 1.5227205E12,			开始时间
     *     "startLongitude": 1.23456789E8,		开始经度
     *     "startLatitude": 4.2345678E7,		开始纬度
     *     "startHeight": 1122.0,				开始高程
     *     "endTime": 0.0,						结束时间
     *     "endLongitude": 0.0,					结束经度
     *     "endLatitude": 0.0,					结束纬度
     *     "endHeight": 0.0						结束高程
     *     "sendToCDcount": 0,					发往成都的次数
     *     "sendTime": 0						最后一次发送时间
     * },
     */
    private TripInfo tripInfo;
    /**
     * 上一个行程的行程ID
     */
    private Integer lastTripID;
    /**
     * 上一个行程的日期
     */
    private LocalDateTime lastTripDay;
    /**
     * 行程跨天标识<br/>
     * 批计算，0：不跨天，1：第一个行程跨天， 2：最后一个行程跨天<br/>
     * 流计算，0：不跨天，1：跨天<br/>
     **/
    private int crossDayFlag;
    /**
     * 流计算使用，跨天行程的前段信息
     */
    private InterCrossDay interCrossDay;

    /**
     * 车辆信息<br/>
     * 轮胎半径、后桥速比、变速箱各挡位速比
     */
    private VehicleInfo vehicleInfo;

    /**
     * 瓦片与区域的对应关系
     */
    private Map<Long,Integer> tileLcMapping;

    /**
     * 流计算使用，使用0200进行事件收集算法链的漏油位置点信息
     */
    private FuelLeakLocation fuelLeakLocation;

    /**
     * 最后一次更新日期，格式:YYYYMMDD
     */
    private String updateDay;

    public CommonData getCommonData() {
        return commonData;
    }
    public void setCommonData(CommonData commonData) {
        this.commonData = commonData;
    }

    /**
     * 获取算法链的事件缓存
     * @return  算法链的事件缓存
     */
    public Map<EventType, OuterEventData> getEventData() {
        return eventData;
    }
    /**
     * 设置算法链的事件缓存
     */
    public void setEventData(Map<EventType, OuterEventData> eventData) {
        this.eventData = eventData;
    }
    /**
     * 获取算法链的特定事件缓存
     * @param type 事件类型
     * @return 特定事件缓存
     */
    public OuterEventData getEventData(EventType type) {
        return this.eventData.get(type);
    }
    /**
     * 设置算法链的特定事件缓存
     */
    public void putEventData(OuterEventData data) {
        this.eventData.put(data.getEvent(), data);
    }
    /**
     * 移除算法链的特定事件缓存
     * @param type 事件类型
     */
    public void removeEventData(EventType type) {
        this.eventData.remove(type);
    }

    /**
     * 获取算法链的统计缓存
     * @return 算法链的统计缓存
     */
    public Map<String, Object> getStatisticData() {
        return statisticData;
    }
    /**
     * 设置算法链的统计缓存
     * @param statisticData 算法链的统计缓存
     */
    public void setStatisticData(Map<String, Object> statisticData) {
        this.statisticData = statisticData;
    }

    /**
     * 获取具体算法的统计缓存
     * @param objName  缓存的key
     * @param objClazz 缓存的对象类型
     * @return 缓存或创建的objClazz类型的对象
     */
    public Object getOrCreateStatisticData(String objName, Class objClazz) {
        Object o = this.statisticData.get(objName);
        if (o == null) {
            try {
                o = objClazz.newInstance();
                this.setStatisticData(objName, o);
            } catch (Exception e) {
                logger.error("", e);
            }
        }
        if (o instanceof Map) {
            o = GsonUtils.gsonToBean(GsonUtils.gsonString(o), objClazz);
            this.setStatisticData(objName, o);
        }

        return o;
    }
    /**
     * 设置具体算法的统计缓存
     * @param objName 算法的类型
     * @param obj   算法的统计变量
     */
    public void setStatisticData(String objName, Object obj) {
        this.statisticData.put(objName, obj);
    }

    /**
     * 获取当前行程信息
     * @return 当前行程信息
     */
    public TripInfo getTripInfo() {
        return tripInfo;
    }
    public void setTripInfo(TripInfo tripInfo) {
        this.tripInfo = tripInfo;
    }

    /**
     * 获取算法链的事件输出列表
     * @return 算法链的事件输出列表
     */
    public List<OuterEventData> getOuterEvent() {
        return outerEvent;
    }
    /**
     * 设置算法链的事件输出列表
     * @param outerEvent 算法链的事件输出列表
     */
    public void setOuterEvent(List<OuterEventData> outerEvent) {
        this.outerEvent = outerEvent;
    }
    /**
     * 将事件缓存放入事件输出列表中
     */
    public void addEventDataToList(OuterEventData data) {
        this.outerEvent.add(data);
    }

    public Integer getLastTripID() {
        return lastTripID;
    }

    public void setLastTripID(Integer lastTripID) {
        this.lastTripID = lastTripID;
    }

    public LocalDateTime getLastTripDay() {
        return lastTripDay;
    }

    public void setLastTripDay(LocalDateTime lastTripDay) {
        this.lastTripDay = lastTripDay;
    }

    public VehicleInfo getVehicleInfo() {
        return vehicleInfo;
    }

    public void setVehicleInfo(VehicleInfo vehicleInfo) {
        this.vehicleInfo = vehicleInfo;
    }

    public Map<Long, Integer> getTileLcMapping() {
        return tileLcMapping;
    }

    public void setTileLcMapping(Map<Long, Integer> tileLcMapping) {
        this.tileLcMapping = tileLcMapping;
    }

    public int getCrossDayFlag() {
        return crossDayFlag;
    }

    public void setCrossDayFlag(int crossDayFlag) {
        this.crossDayFlag = crossDayFlag;
    }

    public InterCrossDay getInterCrossDay() {
        return interCrossDay;
    }

    public void setInterCrossDay(InterCrossDay interCrossDay) {
        this.interCrossDay = interCrossDay;
    }

    public String getUpdateDay() {
        return updateDay;
    }

    public void setUpdateDay(String updateDay) {
        this.updateDay = updateDay;
    }

    public FuelLeakLocation getFuelLeakLocation() {
        return fuelLeakLocation;
    }

    public void setFuelLeakLocation(FuelLeakLocation fuelLeakLocation) {
        this.fuelLeakLocation = fuelLeakLocation;
    }

    /**
     * 清空中间缓存变量的值
     */
    public void clear(){
        commonData.clear();
        eventData.clear();
        statisticData.clear();

        tripInfo = null;
        outerEvent.clear();

        //清空流计算的前半段跨天信息
        //crossDayFlag不能清除，因为批计算存储的是昨天的跨天标志
        interCrossDay = null;
    }

    @Override
    public String toString() {
        return "DrivingData{" +
                "commonData=" + commonData +
                ", statisticData=" + statisticData +
                ", eventData=" + eventData +
                ", tripInfo=" + tripInfo +
                ", outerEvent=" + outerEvent +
                ", lastTripID=" + lastTripID +
                ", lastTripDay=" + lastTripDay +
                ", crossDayFlag=" + crossDayFlag +
                ", interCrossDay=" + interCrossDay +
                ", vehicleInfo=" + vehicleInfo +
                ", tileLcMapping=" + tileLcMapping +
                ", fuelLeakLocation=" + fuelLeakLocation +
                ", updateDay='" + updateDay + '\'' +
                '}';
    }
}
